<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
    />
    <meta
      name="description"
      content="Dynamically rotate a model's wheels based on its velocity using node transformations."
    />
    <meta name="cesium-sandcastle-labels" content="Showcases" />
    <title>Cesium Demo</title>
    <script type="text/javascript" src="../Sandcastle-header.js"></script>
    <script
      type="text/javascript"
      src="../../../Build/CesiumUnminified/Cesium.js"
      nomodule
    ></script>
    <script type="module" src="../load-cesium-es6.js"></script>
  </head>
  <body
    class="sandcastle-loading"
    data-sandcastle-bucket="bucket-requirejs.html"
  >
    <style>
      @import url(../templates/bucket.css);
    </style>
    <div id="cesiumContainer" class="fullSize"></div>
    <div id="loadingOverlay"><h1>Loading...</h1></div>
    <div id="toolbar"></div>
    <script id="cesium_sandcastle_script">
      function startup(Cesium) {
        "use strict";
        //Sandcastle_Begin
        var viewer = new Cesium.Viewer("cesiumContainer", {
          shouldAnimate: true,
        });

        //Make sure viewer is at the desired time.
        var start = Cesium.JulianDate.fromDate(new Date(2018, 11, 12, 15));
        var totalSeconds = 10;
        var stop = Cesium.JulianDate.addSeconds(
          start,
          totalSeconds,
          new Cesium.JulianDate()
        );
        viewer.clock.startTime = start.clone();
        viewer.clock.stopTime = stop.clone();
        viewer.clock.currentTime = start.clone();
        viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP;
        viewer.timeline.zoomTo(start, stop);

        // Create a path for our vehicle by lerping between two positions.
        var position = new Cesium.SampledPositionProperty();
        var startPosition = new Cesium.Cartesian3(
          -2379556.799372864,
          -4665528.205030263,
          3628013.106599678
        );
        var endPosition = new Cesium.Cartesian3(
          -2379603.7074103747,
          -4665623.48990283,
          3627860.82704567
        );
        // A velocity vector property will give us the entity's speed and direction at any given time.
        var velocityVectorProperty = new Cesium.VelocityVectorProperty(
          position,
          false
        );
        var velocityVector = new Cesium.Cartesian3();
        // Store the wheel's rotation over time in a SampledProperty.
        var wheelAngleProperty = new Cesium.SampledProperty(Number);
        var wheelAngle = 0;

        var numberOfSamples = 100;
        for (var i = 0; i <= numberOfSamples; ++i) {
          var factor = i / numberOfSamples;
          var time = Cesium.JulianDate.addSeconds(
            start,
            factor * totalSeconds,
            new Cesium.JulianDate()
          );

          // Lerp using a non-linear factor so that the vehicle accelerates.
          var locationFactor = Math.pow(factor, 2);
          var location = Cesium.Cartesian3.lerp(
            startPosition,
            endPosition,
            locationFactor,
            new Cesium.Cartesian3()
          );
          position.addSample(time, location);
          // Rotate the wheels based on how fast the vehicle is moving at each timestep.
          velocityVectorProperty.getValue(time, velocityVector);
          var metersPerSecond = Cesium.Cartesian3.magnitude(velocityVector);
          var wheelRadius = 0.52; //in meters.
          var circumference = Math.PI * wheelRadius * 2;
          var rotationsPerSecond = metersPerSecond / circumference;

          wheelAngle +=
            ((Math.PI * 2 * totalSeconds) / numberOfSamples) *
            rotationsPerSecond;
          wheelAngleProperty.addSample(time, wheelAngle);
        }

        function updateSpeedLabel(time, result) {
          velocityVectorProperty.getValue(time, velocityVector);
          var metersPerSecond = Cesium.Cartesian3.magnitude(velocityVector);
          var kmPerHour = Math.round(metersPerSecond * 3.6);

          return kmPerHour + " km/hr";
        }

        var rotationProperty = new Cesium.CallbackProperty(function (
          time,
          result
        ) {
          return Cesium.Quaternion.fromAxisAngle(
            Cesium.Cartesian3.UNIT_X,
            wheelAngleProperty.getValue(time),
            result
          );
        },
        false);

        var wheelTransformation = new Cesium.NodeTransformationProperty({
          rotation: rotationProperty,
        });

        var nodeTransformations = {
          Wheels: wheelTransformation,
          Wheels_mid: wheelTransformation,
          Wheels_rear: wheelTransformation,
        };

        // Add our vehicle model.
        var vehicleEntity = viewer.entities.add({
          position: position,
          orientation: new Cesium.VelocityOrientationProperty(position), // Automatically set the vehicle's orientation to the direction it's facing.
          model: {
            uri: "../../SampleData/models/GroundVehicle/GroundVehicle.glb",
            runAnimations: false,
            nodeTransformations: nodeTransformations,
          },
          label: {
            text: new Cesium.CallbackProperty(updateSpeedLabel, false),
            font: "20px sans-serif",
            showBackground: true,
            distanceDisplayCondition: new Cesium.DistanceDisplayCondition(
              0.0,
              100.0
            ),
            eyeOffset: new Cesium.Cartesian3(0, 3.5, 0),
          },
        });

        viewer.trackedEntity = vehicleEntity;
        vehicleEntity.viewFrom = new Cesium.Cartesian3(-10.0, 7.0, 4.0);
        //Sandcastle_End
        Sandcastle.finishedLoading();
      }
      if (typeof Cesium !== "undefined") {
        window.startupCalled = true;
        startup(Cesium);
      }
    </script>
  </body>
</html>
